﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Collections;

namespace System.Runtime.CompilerServices
{
  /// <summary>
  /// Attribute required for extension methods in .NET 2
  /// </summary>
  internal sealed class ExtensionAttribute : Attribute { }
}

namespace FreeFlow.Administration
{
  /// <summary>
  /// Helper class with extension methods for EventLogEntry
  /// </summary>
  public static class EventLogEntryHelper
  {
    /// <summary>
    /// Returns a string representation of an event log entry.
    /// </summary>
    /// <param name="entry">The event log entry.</param>
    public static string ToClipboardString(this EventLogEntry entry)
    {
      return "Time: " + entry.TimeWritten.ToString() + Environment.NewLine +
        "Type: " + entry.EntryType.ToString() + Environment.NewLine +
        "Category: " + entry.Category + Environment.NewLine + 
        "Message: " + entry.Message;
    }
  }

  /// <summary>
  /// A collection of event log entries filtered to only include those generated by the engine in the last month
  /// </summary>
  public sealed class EventLog : IList, IEnumerable<EventLogEntry>, IRefreshable
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="EventLog"/> class
    /// </summary>
    public EventLog()
    {
    }

    private List<EventLogEntry> log;
    private void ReadLog()
    {
      if (log == null)
      {
        log = new List<EventLogEntry>();
        System.Diagnostics.EventLog eventLog = new System.Diagnostics.EventLog("Application");
        for (int i = eventLog.Entries.Count - 1; i >= 0; i--)
        {
          try
          {
            EventLogEntry logEntry = eventLog.Entries[i];
            if ((logEntry.Source == "Metastorm Process Engine") || (logEntry.Source == "e-Work Engine") ||
              (logEntry.Source == "Metastorm ECL Support"))
            {
              // don't show anything over a month old
              if (logEntry.TimeWritten.AddMonths(1) < DateTime.Now)
                break;
              log.Add(eventLog.Entries[i]);
            }
          }
          catch (InvalidOperationException)
          {
            // ignore it, probably caused by a dodgy event log entry
          }
        }
      }
    }

    #region IList Members

    int IList.Add(object value)
    {
      throw new NotImplementedException();
    }

    void IList.Clear()
    {
      throw new NotImplementedException();
    }

    bool IList.Contains(object value)
    {
      throw new NotImplementedException();
    }

    int IList.IndexOf(object value)
    {
      throw new NotImplementedException();
    }

    void IList.Insert(int index, object value)
    {
      throw new NotImplementedException();
    }

    /// <summary>
    /// Gets a value indicating whether the <see cref="T:System.Collections.IList"/> has a fixed size.
    /// </summary>
    /// <returns>true if the <see cref="T:System.Collections.IList"/> has a fixed size; otherwise, false.</returns>
    public bool IsFixedSize
    {
      get 
      { 
        return false; 
      }
    }

    /// <summary>
    /// Gets a value indicating whether the <see cref="T:System.Collections.IList"/> is read-only.
    /// </summary>
    /// <returns>true if the <see cref="T:System.Collections.IList"/> is read-only; otherwise, false.</returns>
    public bool IsReadOnly
    {
      get 
      {
        return true;
      }
    }

    void IList.Remove(object value)
    {
      throw new NotImplementedException();
    }

    void IList.RemoveAt(int index)
    {
      throw new NotImplementedException();
    }

    object IList.this[int index]
    {
      get
      {
        ReadLog();
        return log[index];
      }
      set
      {
        throw new NotSupportedException(DatabaseAware.readOnlyListMessage);
      }
    }

    #endregion
    #region ICollection Members

    /// <summary>
    /// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
    /// </summary>
    /// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param>
    /// <param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param>
    /// <exception cref="T:System.ArgumentNullException">
    /// 	<paramref name="array"/> is null.
    /// </exception>
    /// <exception cref="T:System.ArgumentOutOfRangeException">
    /// 	<paramref name="index"/> is less than zero.
    /// </exception>
    /// <exception cref="T:System.ArgumentException">
    /// 	<paramref name="array"/> is multidimensional.
    /// -or-
    /// <paramref name="index"/> is equal to or greater than the length of <paramref name="array"/>.
    /// -or-
    /// The number of elements in the source <see cref="T:System.Collections.ICollection"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>.
    /// </exception>
    /// <exception cref="T:System.ArgumentException">
    /// The type of the source <see cref="T:System.Collections.ICollection"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.
    /// </exception>
    public void CopyTo(EventLogEntry[] array, int index)
    {
      ReadLog();
      log.CopyTo(array, index);
    }

    void ICollection.CopyTo(Array array, int index)
    {
      CopyTo((EventLogEntry[])array, index);
    }

    /// <summary>
    /// Gets the number of event log entries contained in the collection.
    /// </summary>
    /// <returns>The number of event log entries contained in the collection.</returns>
    public int Count
    {
      get 
      {
        ReadLog();
        return log.Count;
      }
    }

    bool ICollection.IsSynchronized
    {
      get 
      { 
        return false; 
      }
    }

    object ICollection.SyncRoot
    {
      get 
      { 
        return null; 
      }
    }

    #endregion
    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
      ReadLog();
      return log.GetEnumerator();
    }

    #endregion
    #region IEnumerable<EventLogEntry> Members

    /// <summary>
    /// Returns an enumerator that iterates through the collection.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
    /// </returns>
    public IEnumerator<EventLogEntry> GetEnumerator()
    {
      ReadLog();
      return log.GetEnumerator();
    }

    #endregion

    #region IRefreshable Members

    /// <summary>
    /// Refreshes the event log.
    /// </summary>
    public void Refresh()
    {
      log = null;
    }

    #endregion
  }
}
